/**
 * 
 */
package org.david.code.dao.impl;

import java.io.Serializable;
import java.math.BigInteger;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.david.code.dao.IGenericDao;
import org.david.code.util.DaoUtil;
import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Projections;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.HibernateTemplate;
import org.springframework.stereotype.Repository;

/**
 * 基于hibernate实现的泛型Dao，满足通用的增删改查(CRUD)的操作
 * 
 * @author davidxiaozhi
 * 
 */
@Repository
public class GenericDaoImpl<T> implements IGenericDao<T> {

	@Resource(name="hibernateTemplate")
	protected HibernateTemplate hibernateTemplate;
	protected Class<T> persistentClass = (Class<T>) DaoUtil.getTypeArguments(
			GenericDaoImpl.class, this.getClass()).get(0);

	public Class<T> getPersistentClass() {
		return persistentClass;
	}

	public void setPersistentClass(Class<T> persistentClass) {
		this.persistentClass = persistentClass;
	}

	/**
	 * {@inheritDoc}
	 */
	public T get(Serializable id) {
		T entity = (T) hibernateTemplate.get(persistentClass, id);
		return entity;
	}
	/**
	 * {@inheritDoc}
	 */
	public int getCount(final DetachedCriteria query) {
		return (Integer) hibernateTemplate.execute(new HibernateCallback() {
			public Object doInHibernate(Session session)
					throws HibernateException, SQLException {
				Criteria criteria = query.getExecutableCriteria(session);
				Integer count = (Integer) criteria.setProjection(
						Projections.rowCount()).uniqueResult();
				if (count == null)
					return 0;
				return count;
			}
		});
	}
	/**
	 * {@inheritDoc}
	 */
	public List<T> getList(final DetachedCriteria query) {
		return (List<T>) hibernateTemplate.execute(new HibernateCallback() {
			public Object doInHibernate(Session session)
					throws HibernateException, SQLException {
				return query.getExecutableCriteria(session).list();
			}
		});
	}
	/**
	 * {@inheritDoc}
	 */
	public List<T> getList(final DetachedCriteria query, final int firstResult,
			final int maxResults) {

		return (List<T>) hibernateTemplate.execute(new HibernateCallback() {
			public Object doInHibernate(Session session)
					throws HibernateException, SQLException {
				return query.getExecutableCriteria(session).setFirstResult(
						firstResult).setMaxResults(maxResults).list();
			}
		});
	}

	/**
	 * {@inheritDoc}
	 */
	public void remove(T object) {
		hibernateTemplate.delete(object);
	}

	/**
	 * {@inheritDoc}
	 */
	public void remove(Serializable id) {
		hibernateTemplate.delete(this.get(id));
	}

	/**
	 * {@inheritDoc}
	 */
	public T save(T object) {
		return (T) hibernateTemplate.merge(object);
	}

	/**
	 * hql更新或者删除
	 * 
	 * @param hql
	 * @param map
	 * @return
	 */
	public int updateOrDelete(final String hql, final Map<String, Object> map) {
		return (Integer) hibernateTemplate.execute(new HibernateCallback() {
			public Object doInHibernate(Session session)
					throws HibernateException, SQLException {
				return session.createQuery(hql).setProperties(map)
						.executeUpdate();
			}
		});
	}

	public List<T> executeHql(final String hql, final Map<String, Object> map) {
		return (List<T>) hibernateTemplate.execute(new HibernateCallback() {
			public Object doInHibernate(Session session)
					throws HibernateException, SQLException {
				return session.createQuery(hql).setProperties(map).list();
			}
		});
	}

	public List<T> getListBySQL(final String sql,
			final Map<String, Object> map, final Class c) {
		return (List<T>) hibernateTemplate.execute(new HibernateCallback() {
			public Object doInHibernate(Session session)
					throws HibernateException, SQLException {
				return session.createSQLQuery(sql).addEntity(c).setProperties(
						map).list();
			}
		});
	}


	public List getListBySQL2(final String sql, final Map<String, Object> map,
			final Class c) {
		return (List<T>) hibernateTemplate.execute(new HibernateCallback() {
			public Object doInHibernate(Session session)
					throws HibernateException, SQLException {
				return session.createSQLQuery(sql).addEntity(c).setProperties(
						map).list();
			}
		});
	}

	public List<Object[]> getListBySQL(final String sql,
			final Map<String, Object> map) {
		System.out.println(sql);
		return (List<Object[]>) hibernateTemplate
				.execute(new HibernateCallback() {
					public Object doInHibernate(Session session)
							throws HibernateException, SQLException {
						return session.createSQLQuery(sql).setProperties(map)
								.list();
					}
				});
	}


	/**
	 * SQL更新或者删除
	 * 
	 * @param hql
	 * @param map
	 * @return
	 */
	public int updateOrDeleteBySQL(final String sql,
			final Map<String, Object> map) {
		return (Integer) hibernateTemplate.execute(new HibernateCallback() {
			public Object doInHibernate(Session session)
					throws HibernateException, SQLException {
				return session.createSQLQuery(sql).setProperties(map)
						.executeUpdate();
			}
		});
	}


	public List<T> getList(final String hql, final Map<String, Object> map) {
		return (List<T>) hibernateTemplate.execute(new HibernateCallback() {
			public Object doInHibernate(Session session)
					throws HibernateException, SQLException {
				return session.createQuery(hql).setProperties(map).list();
			}
		});
	}
	public Integer getCountBySQL(final String sql, final Map<String, Object> map) {
		return (Integer) hibernateTemplate.execute(new HibernateCallback() {
			public Object doInHibernate(Session session)
					throws HibernateException, SQLException {
				BigInteger result = (BigInteger) session.createSQLQuery(sql)
						.setProperties(map).uniqueResult();
				if (result != null) {
					return result.intValue();

				} else {
					return 0;
				}
			}
		});
	}


	public Integer getCount(final String hql, final Map<String, Object> map) {
		return (Integer) hibernateTemplate.execute(new HibernateCallback() {
			public Object doInHibernate(Session session)
					throws HibernateException, SQLException {
				Long result = (Long) session.createQuery(hql)
						.setProperties(map).uniqueResult();
				if (result != null) {
					return result.intValue();

				} else {
					return 0;
				}
			}
		});
	}

	public Session getSession() {
		return (Session) hibernateTemplate.execute(new HibernateCallback() {
			public Object doInHibernate(Session session)
					throws HibernateException, SQLException {
				return session;
			}
		});
	}

	/*********************************** update by lvjun 2011-5-1 ***************************************************/
	/**
	 * 更新一个对象
	 * 
	 * @param object
	 * @return
	 */
	public T update(T object) {
		hibernateTemplate.update(object);
		return object;
	}

	/**
	 * 创建Query
	 * 
	 * @param queryString
	 * @param values
	 * @return
	 */
	public Query createQuery(String queryString) {
		Query query = getSession().createQuery(queryString);
		return query;
	}

	/**
	 * 创建Query
	 * 
	 * @param queryString
	 * @param values
	 * @return
	 */
	public Query createQuery(String queryString, Object... values) {
		Query query = getSession().createQuery(queryString);
		if (values != null) {
			for (int i = 0; i < values.length; i++) {
				query.setParameter(i, values[i]);
			}
		}
		return query;
	}

	/**
	 * Native SQL(原生SQL查询)
	 * 
	 * @param queryString
	 * @return
	 */
	public Query createSQLQuery(String queryString) {
		Query query = getSession().createSQLQuery(queryString);
		return query;
	}

	/**
	 * 获取Session
	 * 
	 * @return
	 */
	public Session getCSession() {
		return hibernateTemplate.getSessionFactory().getCurrentSession();
	}

	/**
	 * 根据HQL语句查询对象，支持不确定个数的参数
	 * 
	 * @param queryString
	 *            HQL语句
	 * @param values
	 *            0-N个参数
	 * @return
	 */
	public List<T> query(String queryString, Object... values) {
		
		return createQuery(queryString, values).list();
	}

	public T getUniqueResult(final DetachedCriteria query) {

		return (T) hibernateTemplate.execute(new HibernateCallback() {
			public Object doInHibernate(Session session)
					throws HibernateException, SQLException {
				return query.getExecutableCriteria(session).uniqueResult();
			}
		});
	}
}
